<?php

class ContentList implements Iterator, Countable {
	/**
	 * Elements of contentList.
	 * Each element instanceof ContentListElement.
	 *
	 * @var array
	 */
	protected $_elements = array();

	/**
	 * ContentList name.
	 *
	 * @var string
	 */
	protected $_name;

	/**
	 * Set name of ContentList.
	 *
	 * @return void
	 */
	public function setName($name) {
		$this->_name = $name;
	}

	/**
	 * Get name of ContentList.
	 *
	 * @return string
	 */
	public function getName() {
		return $this->_name;
	}

	/**
	 * Create new ContentList from Rowset object !! Deprecated, use factoryByInterface(), which do the same things but sounds better :) !!
	 *
	 * @param Zend_Db_Table_Rowset_Abstract
	 * @param string $type
	 * @return ContentList
	 * @throws Exception
	 */
	public static function fromRowset($rowset, $type = null) {
		return self::factoryByInterface($rowset, $type);
	}


	/**
	 * Create new ContentList from array of objects which implements IContentListElementProvider
	 *
	 * @param array
	 * @param string $type
	 * @return ContentList
	 * @throws Exception
	 */
	public static function factoryByInterface($list, $type = null) {
		$contentlist = new self();
		foreach ($list as $interface) {
			$contentlist->addElementByInterface($interface, $type);
		}

		return $contentlist;
	}

	/**
	 * Create new ContentList from array of objects by creating passing them to factory method of content list specified by $className
	 *
	 * @param string $className
	 * @param array $objectList
	 * @return ContentList
	 * @throws Exception
	 */
	public static function factoryByClassName($className, $objectList) {
		$contentlist = new self();

		if (!class_exists($className)) {
			throw new Exception("Class '{$className}' does not exist");
		}

		$data = null;

		$methodName = 'prepareCommonData';

		if (method_exists($className, $methodName)) {
			$callback = array(
				$className,
				$methodName
			);
			call_user_func($callback, $objectList);
		}

		foreach ($objectList as $object) {
			$contentlist->addElementByClassName($className, $object);
		}

		return $contentlist;
	}

	public static function factoryByClass($list, $class) {
		$contentList = new self();
		foreach ($list as $element) {
			$contentListElement = new $class($element);
			$contentList->addElement($contentListElement);
		}

		return $contentList;
	}


	public static function fromRowset2($rowset, $params = array()) {

		$contentlist = ContentListElement::fromRowset($rowset, $params);

		return $contentlist;
	}

	/**
	 * Adding element to ContentList
	 *
	 * @param ContentListElement $element
	 * @return void
	 */
	public function addElement($element) {
		if (!$element instanceof IContentListElement) {
			throw new Exception('Element is not valid ContentListElement');
		}

		$this->_elements[] = $element;
	}

	public function addElementBlog($element) {
		if (!$element instanceof ContentListElementBlog) {
			throw new Exception('Element is not valid ContentListElement');
		}
		$this->_elements[] = $element;
	}

	/**
	 * Adding element to ContentList
	 *
	 * @param ContentListElement $element
	 * @return void
	 */
	public function addElementBefore($element) {
		if (!$element instanceof IContentListElement) {
			throw new Exception('Element is not valid ContentListElement');
		}

		array_unshift($this->_elements, $element);
	}

	/**
	 * Adding element by class implements IContentListElement
	 *
	 * @param IContentListElement $interface
	 * @param string $type
	 * @return void
	 */
	public function addElementByInterface($interface, $type = null) {
		if (!$interface instanceof IContentListElementProvider) {
			throw new Exception('Interface IContentListElementProvider not implemented');
		}

		$element = ContentListElement::fromProvider($interface, $type);
		if ($element)
			$this->addElement($element);
	}

	public function addElementByClassName($className, $object, $data = null) {
		$element = Factory::getObject($className, 'factory', array($object, $data));
		$this->addElement($element);
	}

	/**
	 * Iteration index
	 *
	 * @var integer
	 */
	protected $_index;

	/**
	 * Defined by Countable interface
	 *
	 * @return int
	 */
	public function count() {
		return count($this->_elements);
	}

	/**
	 * Defined by Iterator interface
	 *
	 * @return mixed
	 */
	public function current() {
		return current($this->_elements);
	}

	/**
	 * Defined by Iterator interface
	 *
	 * @return mixed
	 */
	public function key() {
		return key($this->_elements);
	}

	/**
	 * Defined by Iterator interface
	 *
	 */
	public function next() {
		next($this->_elements);
		$this->_index++;
	}

	/**
	 * Defined by Iterator interface
	 *
	 */
	public function rewind() {
		reset($this->_elements);
		$this->_index = 0;
	}

	/**
	 * Defined by Iterator interface
	 *
	 * @return boolean
	 */
	public function valid() {
		return $this->_index < $this->count();
	}

	/**
	 * array_rand() for ContentList
	 * Pick one or more random entries out of an ContentList elements.
	 *
	 * @param integer $numRequired Specifies how many entries you want to pick
	 * @return ContentList
	 */
	public function rand($numRequired) {
		if (!count($this->_elements)) {
			return null;
			throw new Exception('ContentList doesnt contain any elements');
		}

		if ($numRequired < 1) {
			$numRequired = 1;
		}

		if (count($this->_elements) < $numRequired) {
			$numRequired = count($this->_elements);
		}

		$keys = array_rand($this->_elements, $numRequired);
		if (!$keys) return false;
		foreach ($this->_elements as $key => $element) {
			if (!in_array($key, $keys)) {
				unset($this->_elements[$key]);
			}
		}
	}

	/**
	 * Return full url by given hash.
	 *
	 * @return string
	 */
	/*public static function getUrlByHash($hash)
	{
		$prefix = Config::getInstance()->file_transfer->htdocsPath;
		$folder = substr($hash, 0, 2);
		$path = "$prefix/$folder/$hash";
		return $path;
	}*/
}